package com.leyou.order.service.impl;

import com.leyou.client.ItemClient;
import com.leyou.common.enums.ExceptionEnum;
import com.leyou.common.exceptions.LyException;
import com.leyou.common.threadlocals.UserHolder;
import com.leyou.common.utils.BeanHelper;
import com.leyou.common.utils.IdWorker;
import com.leyou.order.config.IdWorkerProperties;
import com.leyou.order.dto.CartDTO;
import com.leyou.order.dto.OrderDTO;
import com.leyou.order.entity.Order;
import com.leyou.order.entity.OrderDetail;
import com.leyou.order.entity.OrderLogistics;
import com.leyou.order.enums.OrderStatusEnum;
import com.leyou.order.mapper.OrderDetailMapper;
import com.leyou.order.mapper.OrderLogisticsMapper;
import com.leyou.order.mapper.OrderMapper;
import com.leyou.order.service.IorderService;
import com.leyou.order.utils.PayHelper;
import com.leyou.search.pojo.SkuDTO;
import com.leyou.user.AddressDTO;
import com.leyou.user.UserClient;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.swing.*;
import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.leyou.common.constants.MQConstants.Exchange.Order_EXCHANGE_NAME;
import static com.leyou.common.constants.MQConstants.RoutingKey.Cart_Delete_KEY;

@Slf4j
@Service
@EnableConfigurationProperties(IdWorkerProperties.class)
public class OrderServiceImpl implements IorderService {
    @Autowired
    private IdWorker idWorker;

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private OrderLogisticsMapper orderLogisticsMapper;

    @Autowired
    private UserClient userClient;

    @Autowired
    private ItemClient itemClient;

    @Autowired
    private AmqpTemplate amqpTemplate;

    //创建订单
    @Override
    @Transactional
    public Long createOrder(OrderDTO orderDTO) {
        Order order = BeanHelper.copyProperties(orderDTO, Order.class);

        long orderId = idWorker.nextId();

        order.setOrderId(orderId);

        order.setUserId(UserHolder.getUser().getId());

        @NotNull List<CartDTO> carts = orderDTO.getCarts();

        List<Long> skuIdList = carts.stream().map(CartDTO::getSkuId).collect(Collectors.toList());

        Map<Long, Integer> map = carts.stream().collect(Collectors.toMap(CartDTO::getSkuId, CartDTO::getNum));


        List<SkuDTO> skuDTOS = itemClient.querySkuByIds(skuIdList);

        List<OrderDetail> details = new ArrayList<>();

        long totalFee = 0;
        for (SkuDTO skuDTO : skuDTOS) {
            int num = map.get(skuDTO.getId());
            totalFee += skuDTO.getPrice() * num;

            OrderDetail detail = new OrderDetail();
            detail.setId(null);
            detail.setImage(StringUtils.substringBefore(skuDTO.getImages(), ","));
            detail.setOrderId(orderId);
            detail.setNum(num);
            detail.setOwnSpec(skuDTO.getOwnSpec());
            detail.setTitle(skuDTO.getTitle());
            detail.setPrice(skuDTO.getPrice());
            detail.setSkuId(skuDTO.getId());
            detail.setCreateTime(new Date());
            detail.setUpdateTime(new Date());
            details.add(detail);
        }
        //商品总价
        order.setTotalFee(totalFee);
        //结账方式
        order.setPaymentType(orderDTO.getPaymentType());
        order.setPostFee(8L);
        //实付金额
        order.setActualFee(totalFee + order.getPostFee()/*-优惠价格*/);

        order.setStatus(OrderStatusEnum.INIT.value());

        int count = orderMapper.insertSelective(order);
        if (1 != count) {
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }

        count = orderDetailMapper.insertList(details);
        if (count != details.size()) {
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }


        AddressDTO addressDTO = userClient.queryAddressById(UserHolder.getUser().getId(), orderDTO.getAddressId());

        OrderLogistics orderLogistics = BeanHelper.copyProperties(addressDTO, OrderLogistics.class);
        orderLogistics.setOrderId(orderId);

        count = orderLogisticsMapper.insertSelective(orderLogistics);
        if (1 != count) {
            throw new LyException(ExceptionEnum.INSERT_OPERATION_FAIL);
        }

        itemClient.minusStock(map);

        //下单成功，通过mq把skuid传递过去
        Map<Long, List<Long>> idMap = new HashMap<>();
        idMap.put(UserHolder.getUser().getId(), skuIdList);
        amqpTemplate.convertAndSend(Order_EXCHANGE_NAME, Cart_Delete_KEY, idMap);

        return orderId;
    }

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private PayHelper payHelper;

    //获取微信支付URL
    @Override
    public String getPayUrl(Long orderId) {
        String key = "ly.pay.url" + orderId;
        if (redisTemplate.hasKey(key)) {
            String queryUrl = redisTemplate.opsForValue().get(key);
            if (StringUtils.isNoneBlank(queryUrl)) {
                return queryUrl;
            }
        }
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if (null == order) {
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        Integer status = order.getStatus();
        if (!status.equals(OrderStatusEnum.INIT.value())) {
            throw new LyException(ExceptionEnum.INVALID_ORDER_STATUS);
        }

        Long actualPay = /*order.getActualPay()*/ 1L;

        String desc = "不可描述";

        String url = payHelper.createOrder(orderId, actualPay, desc);

        redisTemplate.opsForValue().set(key, url, 2, TimeUnit.HOURS);

        return url;

    }

    //查询订单状态
    @Override
    public Order queryOrder(Long orderId) {
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if (null == order) {
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        return order;
    }

    //微信回调函数校验
    @Override
    public void handleNotify(Map<String, String> result) {
        //微信签名校验
        try {
            payHelper.isValidSign(result);
        } catch (Exception e) {
            log.error("【微信回调】微信签名有误！, result: {}", result, e);
            throw new LyException(ExceptionEnum.INVALID_NOTIFY_SIGN, e);
        }

        //业务状态校验
        payHelper.checkResultCode(result);

        //校验金额数据
        String totalFeeStr = result.get("total_fee");
        String orderIdStr = result.get("out_trade_no");
        if (StringUtils.isBlank(totalFeeStr) && StringUtils.isBlank(orderIdStr)) {
            throw new LyException(ExceptionEnum.INVALID_NOTIFY_PARAM);
        }

        Long totalFee = Long.valueOf(totalFeeStr);
        Long orderId = Long.valueOf(orderIdStr);

        Order order = orderMapper.selectByPrimaryKey(orderId);

        if (!order.getStatus().equals(OrderStatusEnum.INIT.value())) {
            return;
        }

        if (totalFee !=/*order.getActualFee()*/1) {
            throw new LyException(ExceptionEnum.INVALID_PARAM_ERROR);
        }

        Order orderStatus = new Order();
        orderStatus.setOrderId(orderId);
        orderStatus.setPayTime(new Date());
        orderStatus.setStatus(OrderStatusEnum.PAY_UP.value());
        int count = orderMapper.updateByPrimaryKeySelective(orderStatus);

        if (count != 1) {
            log.error("【微信回调】更新订单状态失败，订单id：{}", orderId);
            throw new LyException(ExceptionEnum.UPDATE_OPERATION_FAIL);
        }
        log.info("【微信回调】, 订单支付成功! 订单编号:{}", orderId);

    }

    //查询订单支付状态
    @Override
    public Integer queryPayState(Long orderId) {
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if (null == order) {
            log.error("【查询订单状态】订单不存在，订单id：{}", orderId);
            throw new LyException(ExceptionEnum.ORDER_NOT_FOUND);
        }
        log.info("【查询订单状态】订单查询成功，订单id：{}", orderId);
        return order.getStatus();
    }

    //清理过期定单
    public void closeOverdueOrders(List<Order> orders) {
        //变更订单状态
        for (Order order : orders) {
            order.setStatus(OrderStatusEnum.CLOSED.value());
            order.setCloseTime(new Date());
            int count = orderMapper.updateByPrimaryKeySelective(order);
            if (count != 1) {
                throw new LyException(ExceptionEnum.UPDATE_OPERATION_FAIL);
            }
        }
        log.info("【订单服务】关闭的订单数量" + orders.size());
        //加库存
        List<OrderDetail> orderDetails = new ArrayList<>();
        for (Order order : orders) {
            OrderDetail orderDetail = new OrderDetail();
            orderDetail.setOrderId(order.getOrderId());
            orderDetails.addAll(orderDetailMapper.select(orderDetail));
            if (CollectionUtils.isEmpty(orderDetails)) {
                throw new LyException(ExceptionEnum.ORDER_DETAIL_NOT_FOUND);
            }
        }
        Map<Long, Integer> plusMap = new HashMap<>();
        orderDetails.forEach(orderDetail -> {
            Long skuId = orderDetail.getSkuId();
            if (plusMap.containsKey(skuId)) {
                Integer num = plusMap.get(skuId);
                plusMap.put(skuId,orderDetail.getNum()+num);
            }else {
                plusMap.put(skuId,orderDetail.getNum());
            }
        });

        itemClient.plusStock(plusMap);

    }

    //查询未支付
    public List<Order> queryOrderByStatus(int status) {
        Order order = new Order();
        order.setStatus(status);
        List<Order> orders = orderMapper.select(order);
        if (CollectionUtils.isEmpty(orders)) {
            log.info("【订单服务】没有需要清理的订单");
        }
        return orders;
    }
}
